home *** CD-ROM | disk | FTP | other *** search
- /*-
- * Copyright (c) 1993 Michael B. Durian. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Michael B. Durian.
- * 4. The name of the the Author may be used to endorse or promote
- * products derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- /*
- * mpu_bsd386.c,v 1.9 1993/05/07 17:45:20 durian Exp
- */
-
- #ifdef MIDIPLAY
- static char cvsid[] = "mpu_bsd386.c,v 1.9 1993/05/07 17:45:20 durian Exp";
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/file.h>
- #include <string.h>
- #include <errno.h>
- #include <sys/ioctl.h>
- #include <i386/isa/midiioctl.h>
- #include "mutil.h"
- #include "mdevice.h"
-
- #define MAX_EVENT_SIZE 256
- /* global */
- volatile int StopProcessing;
-
- static int adjust_division _ANSI_ARGS_((int division, long *div_ioctl,
- int *tempo_scalar));
- static unsigned char double2tempo _ANSI_ARGS_((double d));
-
- int
- play_tracks(dev, tracks, indices, num, repeat)
- int dev;
- TCHUNK *tracks;
- int *indices;
- int num;
- int repeat;
- {
-
- return (record_tracks(dev, tracks, indices, num, NULL, repeat));
- }
-
- int
- record_tracks(dev, p_tracks, indices, p_num, r_track, repeat)
- int dev;
- TCHUNK *p_tracks;
- int *indices;
- int p_num;
- TCHUNK *r_track;
- int repeat;
- {
- TCHUNK tmptrack;
- struct timeval mwait;
- TCHUNK **track_list;
- int *tscalars;
- fd_set w_select;
- fd_set r_select;
- EVENT_TYPE event_type;
- int endtime;
- int event_len;
- int i;
- int select_return;
- int track_done;
- unsigned char event[MAX_EVENT_SIZE];
-
- tscalars = NULL;
- track_list = NULL;
- if (p_num > 0) {
- /* merge play tracks */
- if ((tscalars = (int *)malloc(sizeof(int) * p_num)) == NULL) {
- sprintf(MidiError, "Out of memory");
- return (0);
- }
- if ((track_list = (TCHUNK **)malloc(sizeof(TCHUNK *) * p_num))
- == NULL) {
- sprintf(MidiError, "Out of memory");
- return (0);
- }
- for (i = 0; i < p_num; i++) {
- tscalars[i] = 1;
- track_list[i] = &p_tracks[i];
-
- }
- init_track(&tmptrack);
- endtime = merge_tracks(&tmptrack, track_list, tscalars, p_num,
- 0);
- event_len = fix2var(endtime, event);
- event[event_len] = METAEOT;
- event[event_len + 1] = 0;
- if (!put_smf_event(&tmptrack, event, event_len + 2)) {
- sprintf(MidiError, "Couldn't add METAEOT event");
- free(tscalars);
- free(track_list);
- free_track(&tmptrack);
- return (0);
- }
- }
-
- StopProcessing = 0;
- do {
- track_done = 0;
- rewind_track(&tmptrack);
- while (!StopProcessing && !track_done) {
- /* select on play */
- FD_ZERO(&w_select);
- if (p_num != 0)
- FD_SET(dev, &w_select);
- /* also on record */
- FD_ZERO(&r_select);
- if (r_track != NULL)
- FD_SET(dev, &r_select);
- /*
- * we time out every so often to check and see
- * if StopProcessing has changed
- */
- mwait.tv_sec = 0;
- mwait.tv_usec = 100000;
- if ((select_return = select(getdtablesize(), &r_select,
- &w_select, NULL, &mwait)) == -1) {
- if (errno == EINTR)
- break;
- else {
- sprintf(MidiError,
- "Error in select: %s",
- sys_errlist[errno]);
- if (tscalars != NULL)
- free(tscalars);
- if (track_list != NULL)
- free(track_list);
- free_track(&tmptrack);
- return (0);
- }
- }
- if (StopProcessing)
- break;
- if (select_return == 0)
- continue;
-
- /* write event if not blocked */
- if (p_num != 0 && FD_ISSET(dev, &w_select)) {
- event_len = get_smf_event(&tmptrack,
- event, &event_type);
- switch (event_len) {
- case -1:
- sprintf(MidiError,
- "Couldn't get event from tmptrack");
- if (tscalars != NULL)
- free(tscalars);
- if (track_list != NULL)
- free(track_list);
- free_track(&tmptrack);
- return (0);
- case 0:
- track_done = 1;
- break;
- default:
- if (write(dev, event, event_len) !=
- event_len) {
- sprintf(MidiError,
- "Error writing event: %s",
- sys_errlist[errno]);
- if (tscalars != NULL)
- free(tscalars);
- if (track_list != NULL)
- free(track_list);
- free_track(&tmptrack);
- return (0);
- }
- break;
- }
- }
-
-
- if (r_track != NULL && FD_ISSET(dev, &r_select)) {
- if ((event_len = read(dev, event,
- MAX_EVENT_SIZE)) == -1) {
- sprintf(MidiError,
- "Error reading event: %s",
- sys_errlist[errno]);
- if (tscalars != NULL)
- free(tscalars);
- if (track_list != NULL)
- free(track_list);
- free_track(&tmptrack);
- return (0);
- }
- if (!put_smf_event(r_track, event, event_len)) {
- sprintf(MidiError,
- "Coudln't put smf event");
- if (tscalars != NULL)
- free(tscalars);
- if (track_list != NULL)
- free(track_list);
- free_track(&tmptrack);
- return (0);
- }
- }
- }
- } while (repeat && !StopProcessing);
-
- if (!StopProcessing) {
- /* this waits until we're done playing */
- if (ioctl(dev, MFLUSHQ, NULL) == -1)
- sprintf(MidiError, "Error flushing queue: %s",
- sys_errlist[errno]);
- /* check for any final data to be read */
- FD_ZERO(&r_select);
- if (r_track != NULL)
- FD_SET(dev, &r_select);
- mwait.tv_sec = 0;
- mwait.tv_usec = 0;
- if ((select_return = select(getdtablesize(), NULL, &w_select,
- NULL, &mwait)) == -1) {
- if (errno != EINTR) {
- sprintf(MidiError, "Error in select: %s",
- sys_errlist[errno]);
- if (tscalars != NULL)
- free(tscalars);
- if (track_list != NULL)
- free(track_list);
- free_track(&tmptrack);
- return (0);
- }
- }
- if (r_track != NULL && FD_ISSET(dev, &r_select)) {
- if ((event_len = read(dev, event, MAX_EVENT_SIZE))
- == -1) {
- sprintf(MidiError, "Error reading event: %s",
- sys_errlist[errno]);
- if (tscalars != NULL)
- free(tscalars);
- if (track_list != NULL)
- free(track_list);
- free_track(&tmptrack);
- return (0);
- }
- if (!put_smf_event(r_track, event, event_len)) {
- sprintf(MidiError, "Coudln't put smf event");
- if (tscalars != NULL)
- free(tscalars);
- if (track_list != NULL)
- free(track_list);
- free_track(&tmptrack);
- return (0);
- }
- }
- }
- if (tscalars != NULL)
- free(tscalars);
- if (track_list != NULL)
- free(track_list);
- free_track(&tmptrack);
- return (1);
- }
-
- int
- stop_processing(dev)
- int dev;
- {
-
- StopProcessing = 1;
- /* if we leave, leave now - don't hang on close */
- if (ioctl(dev, MCLRQ, NULL) == -1) {
- sprintf(MidiError, "Error clearing queue: %s",
- sys_errlist[errno]);
- return (0);
- }
- return (0);
- }
-
- int
- open_midi_device(mode)
- PlayMode mode;
- {
- mode_t m;
- int dev;
-
- switch (mode) {
- case PLAY:
- m = O_WRONLY;
- break;
- case RECORD:
- m = O_RDONLY;
- break;
- case PLAYRECORD:
- m = O_RDWR;
- break;
- }
- if ((dev = open("/dev/midi0", m)) == -1) {
- sprintf(MidiError, "Couldn't open /dev/midi0: %s",
- sys_errlist[errno]);
- }
- return (dev);
- }
-
- int
- init_midi_device(dev, hd, reltempo)
- int dev;
- HCHUNK *hd;
- double reltempo;
- {
- long div_ioctl;
- int tscalar;
- unsigned char fixreltempo;
-
- if (!adjust_division(hd->division, &div_ioctl, &tscalar)) {
- sprintf(MidiError, "Bad division value. Must be on of \
- 48, 72, 96, 120, 144, 168, 192 or an integer multiple thereof");
- return (0);
- }
-
- if (ioctl(dev, div_ioctl, NULL) == -1) {
- sprintf(MidiError, "Couldn't set division: %s",
- sys_errlist[errno]);
- return (0);
- }
- if (ioctl(dev, MTSCALAR, &tscalar) == -1) {
- sprintf(MidiError, "Couldn't set tscalar: %s",
- sys_errlist[errno]);
- return (0);
- }
- fixreltempo = double2tempo(reltempo);
- if (ioctl(dev, MSETRELTMP, &fixreltempo) == -1) {
- sprintf(MidiError, "Couldn't set relative tempo: %s",
- sys_errlist[errno]);
- return (0);
- }
-
- return (1);
- }
-
- int
- start_midi_device(dev, mode)
- int dev;
- PlayMode mode;
- {
-
- /* automatically started by open */
- return (1);
- }
-
- int
- stop_midi_device(dev, mode)
- int dev;
- PlayMode mode;
- {
- /* automatically stopped by close */
- return (1);
- }
-
- int
- close_midi_device(dev)
- int dev;
- {
-
- close(dev);
- return (1);
- }
-
- int
- adjust_division(division, div_ioctl, tempo_scalar)
- int division;
- long *div_ioctl;
- int *tempo_scalar;
- {
- long ioctls[] = {MRES192, MRES168, MRES144, MRES120, MRES96,
- MRES72, MRES48};
- int divs[] = {192, 168, 144, 120, 96, 72, 48};
- int i;
- int ret_val;
-
- ret_val = 0;
- for (i = 0; i < sizeof(divs) / sizeof(divs[0]); i++) {
- if (division % divs[i] == 0) {
- *div_ioctl = ioctls[i];
- *tempo_scalar = 1000 * division / divs[i];
- ret_val = 1;
- break;
- }
- }
- return (ret_val);
- }
-
- unsigned char
- double2tempo(d)
- double d;
- {
- double bit_vals[] = {2.0, 1.0, 0.5, 0.25, 0.125, 0.0625,
- 0.03125, 0.015625};
- int i;
- unsigned char tempo_scalar;
-
- for (i = 0; i < 8; i++) {
- if (d < bit_vals[i])
- tempo_scalar = (tempo_scalar << 1) & ~1;
- else {
- tempo_scalar = (tempo_scalar << 1) | 1;
- d -= bit_vals[i];
- }
- }
- return(tempo_scalar);
- }
- #endif
-